package com.xbongbong.paas.script.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasStageEntity;
import com.xbongbong.paas.domain.entity.StageProcessEntity;
import com.xbongbong.paas.enums.StageTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.pro.enums.errorcodes.ClueErrorCodeEnum;
import com.xbongbong.saas.help.StageHelp;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.StageProcessModel;
import com.xbongbong.paas.pojo.dto.FixDataJobDTO;
import com.xbongbong.paas.service.stage.StageHandleFactory;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ClueStageEntity;
import com.xbongbong.saas.domain.entity.ClueStageLogEntity;
import com.xbongbong.saas.domain.entity.CustomerStageEntity;
import com.xbongbong.saas.domain.entity.CustomerStageLogEntity;
import com.xbongbong.saas.domain.entity.OpportunityStageLogEntity;
import com.xbongbong.saas.domain.entity.SaleStageEntity;
import com.xbongbong.saas.domain.entity.StageWorkEntity;
import com.xbongbong.saas.enums.FormConfigEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.help.StageHelp;
import com.xbongbong.saas.model.ClueStageLogModel;
import com.xbongbong.saas.model.ClueStageModel;
import com.xbongbong.saas.model.CustomerStageLogModel;
import com.xbongbong.saas.model.CustomerStageModel;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.saas.model.OpportunityStageLogModel;
import com.xbongbong.saas.model.SaleStageModel;
import com.xbongbong.saas.model.StageWorkModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.model.CompanyModel;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 系统表单阶段相关数据据表数据初始化
 *
 * @author guojun.hu
 * @version v1.0
 * @date 2021/11/18 15:15
 * @since v1.0
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/script/stage")
public class StageInitScriptController {

    private static final Logger LOG = LoggerFactory.getLogger(StageInitScriptController.class);

    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private FormConfigModel formConfigModel;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private StageProcessModel stageProcessModel;
    @Resource
    private CustomerStageModel customerStageModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SaleStageModel saleStageModel;
    @Resource
    private ClueStageModel clueStageModel;
    @Resource
    private StageWorkModel stageWorkModel;
    @Resource
    private CustomerStageLogModel customerStageLogModel;
    @Resource
    private OpportunityStageLogModel opportunityStageLogModel;
    @Resource
    private ClueStageLogModel clueStageLogModel;
    @Resource
    private StageHelp stageHelp;
    @Resource
    private StageHandleFactory stageHandleFactory;

    /**
     * tb_stage_process表初始化
     * 查询tb_paas_form表生成记录，清除每个公司的阶段缓存
     * 查询tb_form_config表获取allow_back字段的初始值
     */
    @RequestMapping(value = "/initStageProcess", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initStageProcess(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            corpidList = companyModel.getCorpidList();
        }
        LOG.warn("数据库中共有公司{}家", corpidList.size());

        Map<String, Object> configParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        configParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        configParam.put("del", 0);
        configParam.put("configIn", Arrays.asList(FormConfigEnum.CUSTOMER_BACK_STAGE_BUTTON.getConfig(),
                FormConfigEnum.SALE_BACK_STAGE_BUTTON.getConfig(), FormConfigEnum.CLUE_BACK_STAGE_BUTTON.getConfig()));
        List<FormConfigEntity> formConfigList = formConfigModel.findEntitys(configParam);
        // 正常来说FormConfig里面的同一个formId的某项配置只会存在一个，如果存在多个说明数据有异常。这里兼容一下异常场景，重复的时候用后面的配置覆盖前面的配置
        Map<String, String> configValueMap = formConfigList.stream()
                .collect(Collectors.toMap(formConfig -> formConfig.getFormId() + "_" + formConfig.getConfig(), FormConfigEntity::getConfigValue, (v1, v2) -> v2));
        LOG.warn("FormConfig配置查询成功");

        // form数据约40w
        Map<String, Object> formParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        formParam.put("del", 0);
        formParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        formParam.put("businessTypeList", Arrays.asList(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(),
                XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), XbbRefTypeEnum.CLUE.getCode()));
        formParam.put("distributorMark", DistributorMarkEnum.OTHER.getCode());
        formParam.put("corpidIn", corpidList);
        formParam.put("columns", "id,corpid,business_type");
        List<PaasFormEntity> paasFormList = paasFormModel.findEntity(formParam);
        int totalFormCount = paasFormList.size();
        LOG.warn("开始初始化阶段流程，数据库中需要生成阶段流程的form共有{}条", totalFormCount);

        // 每1000条数据进行分页处理，计算分页页数
        int pageSize = 1000;
        int pageNum = totalFormCount % pageSize > 0 ? totalFormCount / pageSize + 1 : totalFormCount / pageSize;
        for (int currentPage = 1; currentPage <= pageNum; currentPage++) {
            int startIndex = (currentPage - 1) * pageSize;
            int endIndex = currentPage * pageSize;
            if (Objects.equals(currentPage, pageNum)) {
                endIndex = totalFormCount;
            }
            LOG.warn("开始初始化第{}——{}条数据，一共{}条数据，进度{}/{}", startIndex, endIndex, totalFormCount, currentPage, pageNum);

            // 当前分页处理的from数据
            List<PaasFormEntity> currentInitPaasFormList = paasFormList.subList(startIndex, endIndex);
            List<StageProcessEntity> stageProcessList = new ArrayList<>();
            for (PaasFormEntity paasForm : currentInitPaasFormList) {
                Integer businessType = paasForm.getBusinessType();
                String corpid = paasForm.getCorpid();
                Long formId = paasForm.getId();
                String configKey = formId + "_";
                if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode())) {
                    configKey = configKey + FormConfigEnum.CUSTOMER_BACK_STAGE_BUTTON.getConfig();
                } else if (Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode())) {
                    configKey = configKey + FormConfigEnum.SALE_BACK_STAGE_BUTTON.getConfig();
                } else if (Objects.equals(businessType, XbbRefTypeEnum.CLUE.getCode())) {
                    configKey = configKey + FormConfigEnum.CLUE_BACK_STAGE_BUTTON.getConfig();
                }
                // 老逻辑：没有配置-允许；0-不允许；1-允许
                String allowBackConfigValue = configValueMap.getOrDefault(configKey, BasicConstant.ONE_STRING);
                Integer allowBack = StringUtil.toInt(allowBackConfigValue, BasicConstant.ZERO);
                StageProcessEntity stageProcess = new StageProcessEntity();
                stageProcess.initStageProcess(corpid, formId, allowBack, 1);
                stageProcessList.add(stageProcess);
            }
            if (CollectionsUtil.isNotEmpty(stageProcessList)) {
                stageProcessModel.insertBatch(stageProcessList);
            }
        }
        LOG.warn("阶段流程初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化客户阶段数据
     */
    @RequestMapping(value = "/initCustomerStage", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initCustomerStage(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            corpidList = companyModel.getCorpidList();
        }
        LOG.warn("数据库中共有公司{}家", corpidList.size());

        // 查询表单解释用于默认选项个选项管理数据迁移
        Map<String, Object> explainParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        explainParam.put("businessType", XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        explainParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        explainParam.put("del", 0);
        explainParam.put("distributorMark", DistributorMarkEnum.OTHER.getCode());

        // 查询需要初始化的阶段，数据约56w
        Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageParam.put("del", 0);
        stageParam.put("corpidIn", corpidList);
        List<CustomerStageEntity> totalStageList = customerStageModel.findEntitys(stageParam);
        // 将所有的普通阶段按照formId进行分组，用于allow_reactive_stage字段处理
        // TODO 初始化allow_reactive_stage字段的时候，对于enable=0的未启用的普通阶段要不要加到allow_reactive_stage字段的数组里
        Map<String, List<Long>> stageMap = totalStageList.stream()
                .filter(stage -> Objects.equals(stage.getType(), StageTypeEnum.ORDINARY_STAGE.getType()))
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId(), stage -> Lists.newArrayList(stage.getId()),
                        (List<Long> oldList, List<Long> newList) -> {
                            oldList.addAll(newList);
                            return oldList;
                        }));
        LOG.warn("开始初始化客户阶段，数据库中需要初始化的客户阶段共有{}条", totalStageList.size());

        // 查询阶段流程，数据约40w
        Map<String, Object> processParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        processParam.put("del", 0);
        processParam.put("oldTransferVersion", 1);
        List<Long> formIdIn = totalStageList.stream().map(CustomerStageEntity::getFormId).distinct().collect(Collectors.toList());
        processParam.put("corpidList", corpidList);
        processParam.put("formIdIn", formIdIn);
        processParam.put("columns", "id,corpid,form_id");
        List<StageProcessEntity> stageProcessList = stageProcessModel.findEntitys(processParam);
        // 这里不指定key值重复时的mergeFunction，如果key值重复了就报错，需要去查一下原因。因为一个公司的一个表单下最多只会存在一个oldTransferVersion=1的流程，多个的时候一定出问题了
        Map<String, StageProcessEntity> stageProcessMap = stageProcessList.stream().collect(Collectors.toMap(
                stageProcess -> stageProcess.getCorpid() + "_" + stageProcess.getFormId(), stageProcess -> stageProcess));

        // 查询是否允许跨阶段的配置项，用于allowSkipStage字段处理
        Map<String, Object> configParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        configParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        configParam.put("del", 0);
        configParam.put("config", FormConfigEnum.CUSTOMER_CROSS_STAGE_BUTTON.getConfig());
        List<FormConfigEntity> formConfigList = formConfigModel.findEntitys(configParam);
        Map<Long, String> configValueMap = formConfigList.stream().collect(Collectors.toMap(FormConfigEntity::getFormId, FormConfigEntity::getConfigValue, (v1, v2) -> v2));

        // 每1000条数据进行分页处理，计算分页页数
        int totalStageCount = totalStageList.size();
        int pageSize = 1000;
        int pageNum = totalStageCount % pageSize > 0 ? totalStageCount / pageSize + 1 : totalStageCount / pageSize;
        for (int currentPage = 1; currentPage <= pageNum; currentPage++) {
            int startIndex = (currentPage - 1) * pageSize;
            int endIndex = currentPage * pageSize;
            if (Objects.equals(currentPage, pageNum)) {
                endIndex = totalStageCount;
            }
            LOG.warn("开始初始化第{}——{}条数据，一共{}条数据，进度{}/{}", startIndex, endIndex, totalStageCount, currentPage, pageNum);

            List<CustomerStageEntity> initCurrentPageStageList = totalStageList.subList(startIndex, endIndex);
            List<String> currentInitCorpidList = initCurrentPageStageList.stream().map(CustomerStageEntity::getCorpid).distinct().collect(Collectors.toList());
            explainParam.put("corpidIn", currentInitCorpidList);
            List<PaasFormExplainEntity> explainList = paasFormExplainModel.findEntitys(explainParam);
            // 理论上一个formId只会有一份解释，如果出现同一个formId存在多份解释的情况就让它报错，需要去查一下原因
            Map<Long, String> explainMap = explainList.stream().collect(Collectors.toMap(PaasFormExplainEntity::getFormId, PaasFormExplainEntity::getExplains));

            for (CustomerStageEntity stage : initCurrentPageStageList) {
                // 设置阶段关联的阶段流程
                String stageGroupKey = stage.getCorpid() + "_" + stage.getFormId();
                StageProcessEntity stageProcess = stageProcessMap.get(stageGroupKey);
                if (Objects.isNull(stageProcess)) {
                    // 没有找到对应的阶段流程大概率是因为form被删除了所以没有初始化阶段流程
                    // 对于这样的阶段没有必要处理
                    continue;
                }
                stage.setStageProcessId(stageProcess.getId());

                // 是否允许跳过阶段 读取
                String allowSkipStageStr = configValueMap.getOrDefault(stage.getFormId(), BasicConstant.ONE_STRING);
                Integer allowSkipStage = StringUtil.toInt(allowSkipStageStr);
                stage.setAllowSkipStage(allowSkipStage);

                // 将原来的进入条件格式进行调整
                String originalPreConditions = stage.getPreConditions();
                if (StringUtil.isNotEmpty(originalPreConditions)) {
                    JSONArray originalPreConditionsArray = FastJsonHelper.parseArray(originalPreConditions);
                    JSONObject itemObj = new JSONObject();
                    itemObj.put("name", "条件1");
                    JSONObject linkAttr = new JSONObject();
                    linkAttr.put("type", 1);
                    linkAttr.put("formId", stage.getFormId());
                    linkAttr.put("attr", "");
                    linkAttr.put("saasMark", SaasMarkEnum.SAAS.getCode());
                    linkAttr.put("businessType", XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
                    itemObj.put("linkAttr", linkAttr);
                    itemObj.put("filter", originalPreConditionsArray);
                    itemObj.put("messageContent", new JSONArray());
                    JSONArray newPreConditionsArray = new JSONArray();
                    newPreConditionsArray.add(itemObj);
                    stage.setPreConditions(newPreConditionsArray.toJSONString());
                }

                // tb_customer_stage表新增extra_setting字段，字段里面的属性【associatedContract】代表阶段是否需要关联合同（0：不需要、1：需要）默认值为0，对当前type=1的数据将【associatedContract】的值置为1
                if (Objects.equals(stage.getType(), StageTypeEnum.SUCCESS_STAGE.getType())) {
                    JSONObject extraSetting = new JSONObject();
                    extraSetting.put("associatedContract", 1);
                    stage.setExtraSetting(extraSetting);
                }

                // allow_reactive字段，普通阶段值为0，成功或失败阶段值为1
                // allow_reactive_stage字段，成功或失败阶段的值为同一个阶段流程下所有type=0的普通阶段的主键id数组
                if (Objects.equals(stage.getType(), StageTypeEnum.SUCCESS_STAGE.getType()) || Objects.equals(stage.getType(), StageTypeEnum.FAIL_STAGE.getType())) {
                    stage.setAllowReactive(1);
                    List<Long> ordinaryStageList = stageMap.get(stageGroupKey);
                    if (CollectionsUtil.isNotEmpty(ordinaryStageList)) {
                        JSONArray allowReactiveStage = JSON.parseArray(JSON.toJSONString(ordinaryStageList));
                        stage.setAllowReactiveStage(allowReactiveStage);
                    }
                }

                // is_default和link_option字段数据迁移
                List<FieldAttrEntity> formExplainList = JSON.parseArray(explainMap.get(stage.getFormId()), FieldAttrEntity.class);
                if (CollectionsUtil.isNotEmpty(formExplainList)) {
                    FieldAttrEntity stageFieldAttrEntity = formExplainList.stream()
                            .filter(fieldAttrEntity -> Objects.equals(fieldAttrEntity.getAttr(), CustomerManagementEnum.CUSTOMER_STAGE.getAttr()))
                            .findFirst().orElse(null);
                    if (Objects.nonNull(stageFieldAttrEntity)) {
                        List<ItemPoJo> stageItems = stageFieldAttrEntity.getItems();
                        if (CollectionsUtil.isNotEmpty(stageItems)) {
                            ItemPoJo itemPoJo = stageItems.stream().filter(item -> Objects.equals(Objects.toString(item.getValue()), stage.getCode())).findFirst().orElse(null);
                            if (Objects.nonNull(itemPoJo)) {
                                Integer isDefault = Objects.nonNull(itemPoJo.getChecked()) && itemPoJo.getChecked() ? 1 : 0;
                                stage.setIsDefault(isDefault);
                                List<String> fieldMap = itemPoJo.getFieldMap();
                                if (CollectionsUtil.isNotEmpty(fieldMap)) {
                                    stage.setLinkOption(FastJsonHelper.parseArray(JSON.toJSONString(fieldMap)));
                                }
                            }
                        }
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(initCurrentPageStageList)) {
                customerStageModel.updateBatch4Script(initCurrentPageStageList);
            }
        }
        LOG.warn("客户阶段初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化机会阶段数据
     */
    @RequestMapping(value = "/initSaleStage", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initSaleStage(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            corpidList = companyModel.getCorpidList();
        }
        LOG.warn("数据库中共有公司{}家", corpidList.size());

        // 查询表单解释用于默认选项个选项管理数据迁移
        Map<String, Object> explainParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        explainParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        explainParam.put("businessType", XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
        explainParam.put("del", 0);
        explainParam.put("distributorMark", DistributorMarkEnum.OTHER.getCode());

        // 查询需要初始化的阶段，数据约33w
        Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageParam.put("del", 0);
        stageParam.put("corpidIn", corpidList);
        List<SaleStageEntity> totalStageList = saleStageModel.findEntitys(stageParam);
        // 将所有的普通阶段按照formId进行分组，用于allow_reactive_stage字段处理
        // TODO 初始化allow_reactive_stage字段的时候，对于enable=0的未启用的普通阶段要不要加到allow_reactive_stage字段的数组里
        Map<String, List<Long>> stageMap = totalStageList.stream()
                .filter(stage -> Objects.equals(stage.getType(), StageTypeEnum.ORDINARY_STAGE.getType()))
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId(), stage -> Lists.newArrayList(stage.getId()),
                        (List<Long> oldList, List<Long> newList) -> {
                            oldList.addAll(newList);
                            return oldList;
                        }));
        LOG.warn("开始初始化机会阶段，数据库中需要初始化的机会阶段共有{}条", totalStageList.size());

        // 将所有的阶段按照formId进行分组，对每个分组按照sort值升序排列，即将阶段从后到前排序好，用于后面的into_proportion字段赋值
        // TODO enable=0的阶段要不要设置into_proportion
        // TODO 获取当前阶段的前一个阶段时要不要跳过enable=0的阶段
        Map<String, List<SaleStageEntity>> saleStageMap = totalStageList.stream().collect(Collectors.groupingBy(stage -> stage.getCorpid() + "_" + stage.getFormId()));
        Map<String, List<SaleStageEntity>> sortedSaleStageMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        saleStageMap.forEach((key, value) -> {
            List<SaleStageEntity> sortedStageList = value.stream().sorted(Comparator.comparing(SaleStageEntity::getSort)).collect(Collectors.toList());
            sortedSaleStageMap.put(key, sortedStageList);
        });

        // 查询阶段流程，数据约40w
        Map<String, Object> processParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        processParam.put("del", 0);
        processParam.put("oldTransferVersion", 1);
        List<Long> formIdIn = totalStageList.stream().map(SaleStageEntity::getFormId).distinct().collect(Collectors.toList());
        processParam.put("corpidList", corpidList);
        processParam.put("formIdIn", formIdIn);
        processParam.put("columns", "id,corpid,form_id");
        List<StageProcessEntity> stageProcessList = stageProcessModel.findEntitys(processParam);
        Map<String, StageProcessEntity> stageProcessMap = stageProcessList.stream().collect(Collectors.toMap(
                stageProcess -> stageProcess.getCorpid() + "_" + stageProcess.getFormId(), stageProcess -> stageProcess));

        // 查询是否允许跨阶段的配置项，用于allowSkipStage字段处理
        Map<String, Object> configParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        configParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        configParam.put("del", 0);
        configParam.put("config", FormConfigEnum.SALE_CROSS_STAGE_BUTTON.getConfig());
        List<FormConfigEntity> formConfigList = formConfigModel.findEntitys(configParam);
        Map<Long, String> configValueMap = formConfigList.stream().collect(Collectors.toMap(FormConfigEntity::getFormId, FormConfigEntity::getConfigValue, (v1, v2) -> v2));

        // 每1000条数据进行分页处理，计算分页页数
        int totalStageCount = totalStageList.size();
        int pageSize = 1000;
        int pageNum = totalStageCount % pageSize > 0 ? totalStageCount / pageSize + 1 : totalStageCount / pageSize;
        for (int currentPage = 1; currentPage <= pageNum; currentPage++) {
            int startIndex = (currentPage - 1) * pageSize;
            int endIndex = currentPage * pageSize;
            if (Objects.equals(currentPage, pageNum)) {
                endIndex = totalStageCount;
            }
            LOG.warn("开始初始化第{}——{}条数据，一共{}条数据，进度{}/{}", startIndex, endIndex, totalStageCount, currentPage, pageNum);

            List<SaleStageEntity> initCurrentPageStageList = totalStageList.subList(startIndex, endIndex);
            List<String> currentInitCorpidList = initCurrentPageStageList.stream().map(SaleStageEntity::getCorpid).distinct().collect(Collectors.toList());
            explainParam.put("corpidIn", currentInitCorpidList);
            List<PaasFormExplainEntity> explainList = paasFormExplainModel.findEntitys(explainParam);
            Map<Long, String> explainMap = explainList.stream().collect(Collectors.toMap(PaasFormExplainEntity::getFormId, PaasFormExplainEntity::getExplains));

            for (SaleStageEntity stage : initCurrentPageStageList) {
                // 设置阶段关联的阶段流程
                String stageGroupKey = stage.getCorpid() + "_" + stage.getFormId();
                StageProcessEntity stageProcess = stageProcessMap.get(stageGroupKey);
                if (Objects.isNull(stageProcess)) {
                    continue;
                }
                stage.setStageProcessId(stageProcess.getId());

                // 是否允许跳过阶段 读取
                String allowSkipStageStr = configValueMap.getOrDefault(stage.getFormId(), BasicConstant.ONE_STRING);
                Integer allowSkipStage = StringUtil.toInt(allowSkipStageStr);
                stage.setAllowSkipStage(allowSkipStage);

                // 将原来的进入条件格式进行调整
                String originalPreConditions = stage.getPreConditions();
                if (StringUtil.isNotEmpty(originalPreConditions)) {
                    JSONArray originalPreConditionsArray = FastJsonHelper.parseArray(originalPreConditions);
                    JSONObject itemObj = new JSONObject();
                    itemObj.put("name", "条件1");
                    JSONObject linkAttr = new JSONObject();
                    linkAttr.put("type", 1);
                    linkAttr.put("formId", stage.getFormId());
                    linkAttr.put("attr", "");
                    linkAttr.put("saasMark", SaasMarkEnum.SAAS.getCode());
                    linkAttr.put("businessType", XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
                    itemObj.put("linkAttr", linkAttr);
                    itemObj.put("filter", originalPreConditionsArray);
                    itemObj.put("messageContent", new JSONArray());
                    JSONArray newPreConditionsArray = new JSONArray();
                    newPreConditionsArray.add(itemObj);
                    stage.setPreConditions(newPreConditionsArray.toJSONString());
                }

                // tb_sale_stage表新增extra_setting字段，字段里面的属性【writeLossReason】代表阶段是否需要选择输单原因（0：不需要、1：需要）默认值为0，对当前type=2的数据将【writeLossReason】的值置为1
                if (Objects.equals(stage.getType(), StageTypeEnum.FAIL_STAGE.getType())) {
                    JSONObject extraSetting = new JSONObject();
                    extraSetting.put("writeLossReason", 1);
                    stage.setExtraSetting(extraSetting);
                }

                // allow_reactive字段，普通阶段值为0，成功或失败或取消阶段值为1
                // allow_reactive_stage字段，成功或失败或取消阶段的值为同一个阶段流程下所有type=0的普通阶段的主键id数组
                boolean isEndStage = Objects.equals(stage.getType(), StageTypeEnum.SUCCESS_STAGE.getType()) ||
                        Objects.equals(stage.getType(), StageTypeEnum.FAIL_STAGE.getType()) ||
                        Objects.equals(stage.getType(), StageTypeEnum.CANCEL_STAGE.getType());
                if (isEndStage) {
                    stage.setAllowReactive(1);
                    List<Long> ordinaryStageList = stageMap.get(stageGroupKey);
                    if (CollectionsUtil.isNotEmpty(ordinaryStageList)) {
                        JSONArray allowReactiveStage = JSON.parseArray(JSON.toJSONString(ordinaryStageList));
                        stage.setAllowReactiveStage(allowReactiveStage);
                    }
                }

                // is_default和link_option字段数据迁移
                List<FieldAttrEntity> formExplainList = JSON.parseArray(explainMap.get(stage.getFormId()), FieldAttrEntity.class);
                if (CollectionsUtil.isNotEmpty(formExplainList)) {
                    FieldAttrEntity stageFieldAttrEntity = formExplainList.stream()
                            .filter(fieldAttrEntity -> Objects.equals(fieldAttrEntity.getAttr(), SalesOpportunityEnum.SALE_STAGE.getAttr()))
                            .findFirst().orElse(null);
                    if (Objects.nonNull(stageFieldAttrEntity)) {
                        List<ItemPoJo> stageItems = stageFieldAttrEntity.getItems();
                        if (CollectionsUtil.isNotEmpty(stageItems)) {
                            ItemPoJo itemPoJo = stageItems.stream().filter(item -> Objects.equals(Objects.toString(item.getValue()), stage.getCode())).findFirst().orElse(null);
                            if (Objects.nonNull(itemPoJo)) {
                                Integer isDefault = Objects.nonNull(itemPoJo.getChecked()) && itemPoJo.getChecked() ? 1 : 0;
                                stage.setIsDefault(isDefault);
                                List<String> fieldMap = itemPoJo.getFieldMap();
                                if (CollectionsUtil.isNotEmpty(fieldMap)) {
                                    stage.setLinkOption(FastJsonHelper.parseArray(JSON.toJSONString(fieldMap)));
                                }
                            }
                        }
                    }
                }

                // 输单阶段和取消阶段不设置进入比例，进入比例=跳出比例=0
                if (Objects.equals(stage.getType(), StageTypeEnum.ORDINARY_STAGE.getType()) || Objects.equals(stage.getType(), StageTypeEnum.SUCCESS_STAGE.getType())) {
                    if (Objects.equals(stage.getType(), StageTypeEnum.SUCCESS_STAGE.getType())) {
                        // 成功阶段的进入比例=跳出比例
                        stage.setIntoProportion(Objects.nonNull(stage.getOutProportion()) ? stage.getOutProportion() : 0);
                        // LOG.warn("当前阶段是成功阶段，sort={}，设置进入比例等于跳出比例{}", stage.getSort(), stage.getOutProportion());
                    } else {
                        // 机会阶段进入比例处理。tb_sale_stage表置入into_proportion的值。置入into_proportion的值为上一个阶段的out_proportion值
                        List<SaleStageEntity> sortedSaleStageList = sortedSaleStageMap.getOrDefault(stageGroupKey, new ArrayList<>());
                        // 获取当前阶段的前一个阶段
                        SaleStageEntity previousStage = sortedSaleStageList.stream()
                                .filter(saleStageEntity -> saleStageEntity.getSort() > stage.getSort()).findFirst().orElse(null);
                        if (Objects.nonNull(previousStage)) {
                            // LOG.warn("当前阶段的sort={}，前一个阶段的sort={}", stage.getSort(), previousStage.getSort());
                            stage.setIntoProportion(Objects.nonNull(previousStage.getOutProportion()) ? previousStage.getOutProportion() : 0);
                        } else {
                            // LOG.warn("当前阶段是第一个阶段，sort={}", stage.getSort());
                        }
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(initCurrentPageStageList)) {
                saleStageModel.updateBatch4Script(initCurrentPageStageList);
            }
        }
        LOG.warn("机会阶段初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化线索阶段数据
     */
    @RequestMapping(value = "/initClueStage", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initClueStage(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (CollectionsUtil.isEmpty(corpidList)) {
            corpidList = companyModel.getCorpidList();
        }
        LOG.warn("开始初始化线索阶段，数据库中共有公司{}家", corpidList.size());

        // 查询表单解释用于默认选项个选项管理数据迁移
        Map<String, Object> explainParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        explainParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        explainParam.put("businessType", XbbRefTypeEnum.CLUE.getCode());
        explainParam.put("del", 0);
        explainParam.put("distributorMark", DistributorMarkEnum.OTHER.getCode());

        // 查询需要初始化的阶段
        Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageParam.put("del", 0);

        // 查询阶段流程
        Map<String, Object> processParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        processParam.put("del", 0);
        processParam.put("oldTransferVersion", 1);

        // 查询是否允许跨阶段的配置项，用于allowSkipStage字段处理
        Map<String, Object> configParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        configParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        configParam.put("del", 0);
        configParam.put("config", FormConfigEnum.CLUE_CROSS_STAGE_BUTTON.getConfig());
        List<FormConfigEntity> formConfigList = formConfigModel.findEntitys(configParam);
        Map<Long, String> configValueMap = formConfigList.stream().collect(Collectors.toMap(FormConfigEntity::getFormId, FormConfigEntity::getConfigValue, (v1, v2) -> v2));

        // 每1000个公司进行分页处理，计算分页页数
        int pageSize = 1000;
        int pageNum = corpidList.size() % pageSize > 0 ? corpidList.size() / pageSize + 1 : corpidList.size() / pageSize;
        for (int currentPage = 1; currentPage <= pageNum; currentPage++) {
            int startIndex = (currentPage - 1) * pageSize;
            int endIndex = currentPage * pageSize;
            if (Objects.equals(currentPage, pageNum)) {
                endIndex = corpidList.size();
            }
            List<String> currentInitCorpidList = corpidList.subList(startIndex, endIndex);
            LOG.warn("开始初始化第{}——{}家公司，进度{}/{}", startIndex, endIndex, currentPage, pageNum);

            explainParam.put("corpidIn", currentInitCorpidList);
            List<PaasFormExplainEntity> explainList = paasFormExplainModel.findEntitys(explainParam);
            Map<Long, String> explainMap = explainList.stream().collect(Collectors.toMap(PaasFormExplainEntity::getFormId, PaasFormExplainEntity::getExplains));

            stageParam.put("corpidIn", currentInitCorpidList);
            List<ClueStageEntity> clueStageList = clueStageModel.findEntitys(stageParam);
            // 将所有的普通阶段按照formId进行分组，用于allow_reactive_stage字段处理
            // TODO 初始化allow_reactive_stage字段的时候，对于enable=0的未启用的普通阶段要不要加到allow_reactive_stage字段的数组里
            Map<String, List<Long>> stageMap = clueStageList.stream()
                    .filter(stage -> Objects.equals(stage.getType(), StageTypeEnum.ORDINARY_STAGE.getType()))
                    .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId(), stage -> Lists.newArrayList(stage.getId()),
                            (List<Long> oldList, List<Long> newList) -> {
                                oldList.addAll(newList);
                                return oldList;
                            }));

            List<Long> formIdIn = clueStageList.stream().map(ClueStageEntity::getFormId).distinct().collect(Collectors.toList());
            processParam.put("corpidList", currentInitCorpidList);
            processParam.put("formIdIn", formIdIn);
            List<StageProcessEntity> stageProcessList = stageProcessModel.findEntitys(processParam);
            Map<String, StageProcessEntity> stageProcessMap = stageProcessList.stream().collect(Collectors.toMap(
                    stageProcess -> stageProcess.getCorpid() + "_" + stageProcess.getFormId(), stageProcess -> stageProcess));

            for (ClueStageEntity stage : clueStageList) {
                // 设置阶段关联的阶段流程
                String stageGroupKey = stage.getCorpid() + "_" + stage.getFormId();
                StageProcessEntity stageProcess = stageProcessMap.get(stageGroupKey);
                if (Objects.isNull(stageProcess)) {
                    continue;
                }
                stage.setStageProcessId(stageProcess.getId());

                // 是否允许跳过阶段 读取
                String allowSkipStageStr = configValueMap.getOrDefault(stage.getFormId(), BasicConstant.ONE_STRING);
                Integer allowSkipStage = StringUtil.toInt(allowSkipStageStr);
                stage.setAllowSkipStage(allowSkipStage);

                // 将原来的进入条件格式进行调整
                String originalPreConditions = stage.getPreConditions();
                if (StringUtil.isNotEmpty(originalPreConditions)) {
                    JSONArray originalPreConditionsArray = FastJsonHelper.parseArray(originalPreConditions);
                    JSONObject itemObj = new JSONObject();
                    itemObj.put("name", "条件1");
                    JSONObject linkAttr = new JSONObject();
                    linkAttr.put("type", 1);
                    linkAttr.put("formId", stage.getFormId());
                    linkAttr.put("attr", "");
                    linkAttr.put("saasMark", SaasMarkEnum.SAAS.getCode());
                    linkAttr.put("businessType", XbbRefTypeEnum.CLUE.getCode());
                    itemObj.put("linkAttr", linkAttr);
                    itemObj.put("filter", originalPreConditionsArray);
                    itemObj.put("messageContent", new JSONArray());
                    JSONArray newPreConditionsArray = new JSONArray();
                    newPreConditionsArray.add(itemObj);
                    stage.setPreConditions(newPreConditionsArray.toJSONString());
                }

                // allow_reactive字段，普通阶段值为0，成功或失败阶段值为1
                // allow_reactive_stage字段，成功或失败阶段的值为同一个阶段流程下所有type=0的普通阶段的主键id数组
                if (Objects.equals(stage.getType(), StageTypeEnum.SUCCESS_STAGE.getType()) || Objects.equals(stage.getType(), StageTypeEnum.FAIL_STAGE.getType())) {
                    stage.setAllowReactive(1);
                    List<Long> ordinaryStageList = stageMap.get(stageGroupKey);
                    if (CollectionsUtil.isNotEmpty(ordinaryStageList)) {
                        JSONArray allowReactiveStage = JSON.parseArray(JSON.toJSONString(ordinaryStageList));
                        stage.setAllowReactiveStage(allowReactiveStage);
                    }
                }

                // is_default和link_option字段数据迁移
                List<FieldAttrEntity> formExplainList = JSON.parseArray(explainMap.get(stage.getFormId()), FieldAttrEntity.class);
                if (CollectionsUtil.isNotEmpty(formExplainList)) {
                    FieldAttrEntity stageFieldAttrEntity = formExplainList.stream()
                            .filter(fieldAttrEntity -> Objects.equals(fieldAttrEntity.getAttr(), ClueEnum.CLUE_STAGE.getAttr()))
                            .findFirst().orElse(null);
                    if (Objects.nonNull(stageFieldAttrEntity)) {
                        List<ItemPoJo> stageItems = stageFieldAttrEntity.getItems();
                        if (CollectionsUtil.isNotEmpty(stageItems)) {
                            ItemPoJo itemPoJo = stageItems.stream().filter(item -> Objects.equals(Objects.toString(item.getValue()), stage.getCode())).findFirst().orElse(null);
                            if (Objects.nonNull(itemPoJo)) {
                                Integer isDefault = Objects.nonNull(itemPoJo.getChecked()) && itemPoJo.getChecked() ? 1 : 0;
                                stage.setIsDefault(isDefault);
                                List<String> fieldMap = itemPoJo.getFieldMap();
                                if (CollectionsUtil.isNotEmpty(fieldMap)) {
                                    stage.setLinkOption(FastJsonHelper.parseArray(JSON.toJSONString(fieldMap)));
                                }
                            }
                        }
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(clueStageList)) {
                clueStageModel.updateBatch4Script(clueStageList);
            }
        }
        LOG.warn("线索阶段初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化阶段工作数据
     */
    @RequestMapping(value = "/initStageWork", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initStageWork(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        LOG.warn("开始初始化阶段工作");

        Map<String, Object> customerStageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        customerStageParam.put("del", 0);
        // customerStageParam.put("corpidIn", customerStageWorkList.stream().map(StageWorkEntity::getCorpid).distinct().collect(Collectors.toList()));
        // customerStageParam.put("formIdIn", customerStageWorkList.stream().map(StageWorkEntity::getFormId).distinct().collect(Collectors.toList()));
        List<CustomerStageEntity> customerStageList = customerStageModel.findEntitys(customerStageParam);
        // 必须确保同一个form下code唯一，老数据存在同一个form下code重复的情况，需要手动清理一下，这里做个兼容
        Map<String, CustomerStageEntity> customerStageMap = customerStageList.stream()
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId() + "_" + stage.getCode(), Function.identity(), (v1, v2) -> v1));

        Map<String, Object> saleStageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        saleStageParam.put("del", 0);
        // saleStageParam.put("corpidIn", saleStageWorkList.stream().map(StageWorkEntity::getCorpid).distinct().collect(Collectors.toList()));
        // saleStageParam.put("formIdIn", saleStageWorkList.stream().map(StageWorkEntity::getFormId).distinct().collect(Collectors.toList()));
        List<SaleStageEntity> saleStageList = saleStageModel.findEntitys(saleStageParam);
        // 必须确保同一个form下code唯一，老数据存在同一个form下code重复的情况，需要手动清理一下，这里做个兼容
        Map<String, SaleStageEntity> saleStageMap = saleStageList.stream()
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId() + "_" + stage.getCode(), Function.identity(), (v1, v2) -> v1));

        Map<String, Object> clueStageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        clueStageParam.put("del", 0);
        // clueStageParam.put("corpidIn", clueStageWorkList.stream().map(StageWorkEntity::getCorpid).distinct().collect(Collectors.toList()));
        // clueStageParam.put("formIdIn", clueStageWorkList.stream().map(StageWorkEntity::getFormId).distinct().collect(Collectors.toList()));
        List<ClueStageEntity> clueStageList = clueStageModel.findEntitys(clueStageParam);
        // 必须确保同一个form下code唯一，老数据存在同一个form下code重复的情况，需要手动清理一下，这里做个兼容
        Map<String, ClueStageEntity> clueStageMap = clueStageList.stream()
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId() + "_" + stage.getCode(), Function.identity(), (v1, v2) -> v1));

        // 查询阶段工作，总数据约271w
        Map<String, Object> stageWorkParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageWorkParam.put("start", 0);
        stageWorkParam.put("pageNum", 10000);
        stageWorkParam.put("del", 0);
        stageWorkParam.put("negCorpid", BasicConstant.ZERO_STRING);
        Long idGte = 0L;
        while (true) {
            stageWorkParam.put("idGte", idGte);
            List<StageWorkEntity> stageWorkList = stageWorkModel.findEntitys(stageWorkParam);
            if (CollectionUtils.isEmpty(stageWorkList)) {
                break;
            }
            idGte = stageWorkList.get(stageWorkList.size() - 1).getId();
            LOG.warn("开始处理id从{}到{}的数据", stageWorkList.get(0).getId(), idGte);

            // Map<Integer, List<StageWorkEntity>> stageWorkMap = stageWorkList.stream().collect(Collectors.groupingBy(StageWorkEntity::getBusinessType));
            // List<StageWorkEntity> customerStageWorkList = stageWorkMap.get(XbbRefTypeEnum.CUSTOMER_STAGE.getCode());
            // List<StageWorkEntity> saleStageWorkList = stageWorkMap.get(XbbRefTypeEnum.SALE_STAGE.getCode());
            // List<StageWorkEntity> clueStageWorkList = stageWorkMap.get(XbbRefTypeEnum.CLUE_STAGE.getCode());

            List<StageWorkEntity> updateStageWorkList = new ArrayList<>();
            for (StageWorkEntity stageWork : stageWorkList) {
                PaasStageEntity stage = null;
                String uniqueKey = stageWork.getCorpid() + "_" + stageWork.getFormId() + "_" + stageWork.getStageCode();
                XbbRefTypeEnum businessType = XbbRefTypeEnum.getByCode(stageWork.getBusinessType());
                switch (businessType) {
                    case CUSTOMER_STAGE:
                        stage = customerStageMap.get(uniqueKey);
                        break;
                    case SALE_STAGE:
                        stage = saleStageMap.get(uniqueKey);
                        break;
                    case CLUE_STAGE:
                        stage = clueStageMap.get(uniqueKey);
                        break;
                    default:
                        break;
                }
                if (Objects.nonNull(stage) && Objects.nonNull(stage.getStageProcessId())) {
                    stageWork.setStageProcessId(stage.getStageProcessId());
                    stageWork.setStageId(stage.getId());
                    updateStageWorkList.add(stageWork);
                }
            }
            if (CollectionsUtil.isNotEmpty(updateStageWorkList)) {
                stageWorkModel.updateBatch4Script(updateStageWorkList);
            }
        }
        LOG.warn("阶段工作初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化客户阶段记录数据
     */
    @RequestMapping(value = "/initCustomerStageLog", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initCustomerStageLog(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        LOG.warn("开始初始化客户阶段记录");

        // 查询阶段，数据约56w
        Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageParam.put("del", 0);
        // stageParam.put("corpidIn", corpidIn);
        // stageParam.put("formIdIn", formIdIn);
        List<CustomerStageEntity> stageList = customerStageModel.findEntitys(stageParam);
        // 必须确保同一个form下code唯一，老数据存在同一个form下code重复的情况，需要手动清理一下，这里做个兼容
        Map<String, CustomerStageEntity> stageMap = stageList.stream()
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId() + "_" + stage.getCode(), Function.identity(), (v1, v2) -> v1));

        // 查询阶段记录，数据约1614w
        Map<String, Object> stageLogParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageLogParam.put("start", 0);
        stageLogParam.put("pageNum", 10000);
        stageLogParam.put("del", 0);
        Long idGte = 0L;
        while (true) {
            stageLogParam.put("idGte", idGte);
            List<CustomerStageLogEntity> stageLogList = customerStageLogModel.findEntitys(stageLogParam);
            if (CollectionUtils.isEmpty(stageLogList)) {
                break;
            }
            idGte = stageLogList.get(stageLogList.size() - 1).getId();
            LOG.warn("开始处理id从{}到{}的数据", stageLogList.get(0).getId(), idGte);

            List<CustomerStageLogEntity> updateStageLogList = new ArrayList<>();
            for (CustomerStageLogEntity stageLog : stageLogList) {
                boolean isNeedUpdate = false;
                String uniqueKey = stageLog.getCorpid() + "_" + stageLog.getFormId() + "_" + stageLog.getStageCode();
                PaasStageEntity stage = stageMap.get(uniqueKey);
                if (Objects.nonNull(stage) && Objects.nonNull(stage.getStageProcessId())) {
                    stageLog.setStageProcessId(stage.getStageProcessId());
                    stageLog.setStageId(stage.getId());
                    stageLog.setStageType(stage.getType());
                    isNeedUpdate = true;
                }
                if (Objects.nonNull(stageLog.getBeforeStageCode())) {
                    String beforeStageUniqueKey = stageLog.getCorpid() + "_" + stageLog.getFormId() + "_" + stageLog.getBeforeStageCode();
                    PaasStageEntity previewStage = stageMap.get(beforeStageUniqueKey);
                    if (Objects.nonNull(previewStage)) {
                        stageLog.setPreStageId(previewStage.getId());
                        isNeedUpdate = true;
                    }
                }
                // 非当前阶段的记录的history_stay_time
                if (!Objects.equals(stageLog.getIsNow(), 1)) {
                    Long outTime = stageLog.getOutTime();
                    Long intoTime = stageLog.getIntoTime();
                    intoTime = Objects.nonNull(intoTime) ? intoTime : 0;
                    if (Objects.nonNull(outTime) && outTime > 0 && outTime > intoTime) {
                        stageLog.setHistoryStayTime(outTime - intoTime);
                        isNeedUpdate = true;
                    }
                }
                if (isNeedUpdate) {
                    updateStageLogList.add(stageLog);
                }
            }
            if (CollectionsUtil.isNotEmpty(updateStageLogList)) {
                customerStageLogModel.updateBatch4Script(updateStageLogList);
            }
        }
        LOG.warn("客户阶段记录初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化机会阶段记录数据
     */
    @RequestMapping(value = "/initSaleStageLog", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initSaleStageLog(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        LOG.warn("开始初始化机会阶段记录");

        // 查询阶段，数据约33w
        Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageParam.put("del", 0);
        // stageParam.put("corpidIn", corpidIn);
        // stageParam.put("formIdIn", formIdIn);
        List<SaleStageEntity> stageList = saleStageModel.findEntitys(stageParam);
        // 必须确保同一个form下code唯一，老数据存在同一个form下code重复的情况，需要手动清理一下，这里做个兼容
        Map<String, SaleStageEntity> stageMap = stageList.stream()
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId() + "_" + stage.getCode(), Function.identity(), (v1, v2) -> v1));

        // 查询阶段记录，数据约226w
        Map<String, Object> stageLogParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageLogParam.put("start", 0);
        stageLogParam.put("pageNum", 10000);
        stageLogParam.put("del", 0);
        Long idGte = 0L;
        while (true) {
            stageLogParam.put("idGte", idGte);
            List<OpportunityStageLogEntity> stageLogList = opportunityStageLogModel.findEntitys(stageLogParam);
            if (CollectionUtils.isEmpty(stageLogList)) {
                break;
            }
            idGte = stageLogList.get(stageLogList.size() - 1).getId();
            LOG.warn("开始处理id从{}到{}的数据", stageLogList.get(0).getId(), idGte);

            List<OpportunityStageLogEntity> updateStageLogList = new ArrayList<>();
            for (OpportunityStageLogEntity stageLog : stageLogList) {
                boolean isNeedUpdate = false;
                String uniqueKey = stageLog.getCorpid() + "_" + stageLog.getFormId() + "_" + stageLog.getStageCode();
                PaasStageEntity stage = stageMap.get(uniqueKey);
                if (Objects.nonNull(stage) && Objects.nonNull(stage.getStageProcessId())) {
                    stageLog.setStageProcessId(stage.getStageProcessId());
                    stageLog.setStageId(stage.getId());
                    stageLog.setStageType(stage.getType());
                    isNeedUpdate = true;
                }
                if (Objects.nonNull(stageLog.getBeforeStageCode())) {
                    String beforeStageUniqueKey = stageLog.getCorpid() + "_" + stageLog.getFormId() + "_" + stageLog.getBeforeStageCode();
                    PaasStageEntity previewStage = stageMap.get(beforeStageUniqueKey);
                    if (Objects.nonNull(previewStage)) {
                        stageLog.setPreStageId(previewStage.getId());
                        isNeedUpdate = true;
                    }
                }
                // 非当前阶段的记录的history_stay_time
                if (!Objects.equals(stageLog.getIsNow(), 1)) {
                    Long outTime = stageLog.getOutTime();
                    Long intoTime = stageLog.getIntoTime();
                    intoTime = Objects.nonNull(intoTime) ? intoTime : 0;
                    if (Objects.nonNull(outTime) && outTime > 0 && outTime > intoTime) {
                        stageLog.setHistoryStayTime(outTime - intoTime);
                        isNeedUpdate = true;
                    }
                }
                if (isNeedUpdate) {
                    updateStageLogList.add(stageLog);
                }
            }
            if (CollectionsUtil.isNotEmpty(updateStageLogList)) {
                opportunityStageLogModel.updateBatch4Script(updateStageLogList);
            }
        }
        LOG.warn("机会阶段记录初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 初始化线索阶段记录数据
     */
    @RequestMapping(value = "/initClueStageLog", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initClueStageLog(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long currentTime = DateTimeUtil.getInt();
        LOG.warn("开始初始化线索阶段记录");

        // 查询阶段，数据约4k
        Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageParam.put("del", 0);
        // stageParam.put("corpidIn", corpidIn);
        // stageParam.put("formIdIn", formIdIn);
        List<ClueStageEntity> stageList = clueStageModel.findEntitys(stageParam);
        // 必须确保同一个form下code唯一，老数据存在同一个form下code重复的情况，需要手动清理一下，这里做个兼容
        Map<String, ClueStageEntity> stageMap = stageList.stream()
                .collect(Collectors.toMap(stage -> stage.getCorpid() + "_" + stage.getFormId() + "_" + stage.getCode(), Function.identity(), (v1, v2) -> v1));

        // 查询阶段记录，数据约37w
        Map<String, Object> stageLogParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stageLogParam.put("start", 0);
        stageLogParam.put("pageNum", 10000);
        stageLogParam.put("del", 0);
        Long idGte = 0L;
        while (true) {
            stageLogParam.put("idGte", idGte);
            List<ClueStageLogEntity> stageLogList = clueStageLogModel.findEntitys(stageLogParam);
            if (CollectionUtils.isEmpty(stageLogList)) {
                break;
            }
            idGte = stageLogList.get(stageLogList.size() - 1).getId();
            LOG.warn("开始处理id从{}到{}的数据", stageLogList.get(0).getId(), idGte);

            List<ClueStageLogEntity> updateStageLogList = new ArrayList<>();
            for (ClueStageLogEntity stageLog : stageLogList) {
                boolean isNeedUpdate = false;
                String uniqueKey = stageLog.getCorpid() + "_" + stageLog.getFormId() + "_" + stageLog.getStageCode();
                PaasStageEntity stage = stageMap.get(uniqueKey);
                if (Objects.nonNull(stage) && Objects.nonNull(stage.getStageProcessId())) {
                    stageLog.setStageProcessId(stage.getStageProcessId());
                    stageLog.setStageId(stage.getId());
                    stageLog.setStageType(stage.getType());
                    isNeedUpdate = true;
                }
                if (Objects.nonNull(stageLog.getBeforeStageCode())) {
                    String beforeStageUniqueKey = stageLog.getCorpid() + "_" + stageLog.getFormId() + "_" + stageLog.getBeforeStageCode();
                    PaasStageEntity previewStage = stageMap.get(beforeStageUniqueKey);
                    if (Objects.nonNull(previewStage)) {
                        stageLog.setPreStageId(previewStage.getId());
                        isNeedUpdate = true;
                    }
                }
                // 非当前阶段的记录的history_stay_time
                if (!Objects.equals(stageLog.getIsNow(), 1)) {
                    Long outTime = stageLog.getOutTime();
                    Long intoTime = stageLog.getIntoTime();
                    intoTime = Objects.nonNull(intoTime) ? intoTime : 0;
                    if (Objects.nonNull(outTime) && outTime > 0 && outTime > intoTime) {
                        stageLog.setHistoryStayTime(outTime - intoTime);
                        isNeedUpdate = true;
                    }
                }
                if (isNeedUpdate) {
                    updateStageLogList.add(stageLog);
                }
            }
            if (CollectionsUtil.isNotEmpty(updateStageLogList)) {
                clueStageLogModel.updateBatch4Script(updateStageLogList);
            }
        }
        LOG.warn("线索阶段记录初始化完成，耗时{}", DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }

    /**
     * 为没有生成过阶段的历史公司生成一份默认的阶段和阶段任务
     */
    @RequestMapping(value = "/initStageAndWorkForProcessWithoutStage", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initStageAndWorkForProcessWithoutStage(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        List<Integer> validBusinessType = Arrays.asList(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), XbbRefTypeEnum.CLUE.getCode());
        Integer businessType = fixDataJobDTO.getBusinessType();
        if (Objects.isNull(businessType) || !validBusinessType.contains(businessType)) {
            throw new XbbException(ClueErrorCodeEnum.API_ERROR_1100100);
        }
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        long currentTime = DateTimeUtil.getInt();
        Integer stageBusinessType = XbbRefTypeEnum.transferBusinessTypeToStageType(businessType);
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        LOG.warn("开始初始化{}阶段", xbbRefTypeEnum.getName());

        // 获取默认阶段
        List<PaasStageEntity> defaultStageList = stageHelp.getDefaultStage(businessType);
        LOG.warn("获取默认阶段成功");
        // 获取默认阶段任务
        List<StageWorkEntity> defaultWorkList = stageHelp.getDefaultStageWork(stageBusinessType);
        Map<String, List<StageWorkEntity>> defaultWorkMap = defaultWorkList.stream().collect(Collectors.groupingBy(StageWorkEntity::getStageCode));
        LOG.warn("获取默认阶段任务成功");

        // 查询阶段流程，数据约38w
        Map<String, Object> processParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        processParam.put("del", 0);
        processParam.put("oldTransferVersion", 1);
        if (CollectionsUtil.isNotEmpty(corpidList)) {
            processParam.put("corpidList", corpidList);
        }
        List<StageProcessEntity> stageProcessList = stageProcessModel.findEntitys(processParam);
        // 将阶段流程按照formId转成map
        Map<Long, StageProcessEntity> processMap = stageProcessList.stream()
                .collect(Collectors.toMap(StageProcessEntity::getFormId, Function.identity(), (v1, v2) -> v2));
        LOG.warn("查询阶段流程成功");

        Set<String> corpidIn = new HashSet<>();
        Set<Long> formIdIn = new HashSet<>();
        stageProcessList.forEach(stageProcess -> {
            corpidIn.add(stageProcess.getCorpid());
            formIdIn.add(stageProcess.getFormId());
        });

        // 查询表单，数据约40w，阶段流程表没有业务类型字段区分，所以每次循环获取阶段流程数据的formId后，再通过form表筛选出具体业务类型的formId
        Map<String, Object> formParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        formParam.put("del", 0);
        formParam.put("saasMark", SaasMarkEnum.SAAS.getCode());
        formParam.put("distributorMark", DistributorMarkEnum.OTHER.getCode());
        formParam.put("businessType", businessType);
        formParam.put("corpidIn", corpidIn);
        formParam.put("idIn", formIdIn);
        formParam.put("columns", "id");
        List<PaasFormEntity> paasFormList = paasFormModel.findEntity(formParam);
        List<Long> formIdList = paasFormList.stream().map(PaasFormEntity::getId).collect(Collectors.toList());
        LOG.warn("查询{}表单成功", xbbRefTypeEnum.getName());

        List<Long> withOutStageFormIdList = new ArrayList<>();
        int totalFormCount = formIdList.size();
        int formPageSize = 10000;
        int formPageNum = totalFormCount % formPageSize > 0 ? totalFormCount / formPageSize + 1 : totalFormCount / formPageSize;
        for (int currentPage = 1; currentPage <= formPageNum; currentPage++) {
            int startIndex = (currentPage - 1) * formPageSize;
            int endIndex = currentPage * formPageSize;
            if (Objects.equals(currentPage, formPageNum)) {
                endIndex = totalFormCount;
            }
            List<Long> currentPageFormList = formIdList.subList(startIndex, endIndex);
            LOG.warn("开始查询第{}——{}个表单关联的阶段，总表单数量{}个，进度{}/{}", startIndex, endIndex, totalFormCount, currentPage, formPageNum);
            List<Long> cloneCurrentPageFormList = new ArrayList<>(currentPageFormList);

            // 获取已经存在阶段的formId
            List<Long> existStageFormIdList;
            List<CustomerStageEntity> customerStageList;
            List<SaleStageEntity> saleStageList;
            List<ClueStageEntity> clueStageList;
            // 查询阶段
            Map<String, Object> stageParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            stageParam.put("del", 0);
            // stageParam.put("corpidIn", corpidIn);
            stageParam.put("formIdIn", currentPageFormList);
            stageParam.put("columns", "form_id");
            switch (xbbRefTypeEnum) {
                case CUSTOMER_MANAGEMENT:
                    customerStageList = customerStageModel.findEntitys(stageParam);
                    existStageFormIdList = customerStageList.stream().map(CustomerStageEntity::getFormId).collect(Collectors.toList());
                    break;
                case SALES_OPPORTUNITY:
                    saleStageList = saleStageModel.findEntitys(stageParam);
                    existStageFormIdList = saleStageList.stream().map(SaleStageEntity::getFormId).collect(Collectors.toList());
                    break;
                case CLUE:
                    clueStageList = clueStageModel.findEntitys(stageParam);
                    existStageFormIdList = clueStageList.stream().map(ClueStageEntity::getFormId).collect(Collectors.toList());
                    break;
                default:
                    throw new XbbException(ClueErrorCodeEnum.API_ERROR_1100100);
            }
            // 从所有的formId中删除已经存在阶段的formId，剩余的就是需要生成默认阶段的formId
            cloneCurrentPageFormList.removeAll(existStageFormIdList);
            withOutStageFormIdList.addAll(cloneCurrentPageFormList);
        }
        LOG.warn("查询阶段成功，需要为{}个表单生成默认的的阶段和任务", withOutStageFormIdList.size());

        // 每pageSize条数据进行分页处理，计算分页页数
        int totalCount = withOutStageFormIdList.size();
        int pageSize = Objects.nonNull(fixDataJobDTO.getPageSize()) ? fixDataJobDTO.getPageSize() : 1000;
        int pageNum = totalCount % pageSize > 0 ? totalCount / pageSize + 1 : totalCount / pageSize;
        for (int currentPage = 1; currentPage <= pageNum; currentPage++) {
            int startIndex = (currentPage - 1) * pageSize;
            int endIndex = currentPage * pageSize;
            if (Objects.equals(currentPage, pageNum)) {
                endIndex = totalCount;
            }
            List<Long> currentInitFormList = withOutStageFormIdList.subList(startIndex, endIndex);
            LOG.warn("开始初始化第{}——{}条数据，总量{}条，进度{}/{}", startIndex, endIndex, totalCount, currentPage, pageNum);

            List<PaasStageEntity> insertStageList = new ArrayList<>();
            currentInitFormList.forEach(formId -> {
                StageProcessEntity stageProcess = processMap.get(formId);
                if (Objects.nonNull(stageProcess)) {
                    List<PaasStageEntity> cloneStageList = (List<PaasStageEntity>) CloneUtil.deepClone(defaultStageList);
                    cloneStageList.forEach(defaultStage -> {
                        defaultStage.setId(null);
                        defaultStage.setCorpid(stageProcess.getCorpid());
                        // defaultStage.setCode(UUID.randomUUID().toString());
                        defaultStage.setFormId(formId);
                        defaultStage.setStageProcessId(stageProcess.getId());
                        defaultStage.setAddTime(DateTimeUtil.getInt());
                        defaultStage.setUpdateTime(DateTimeUtil.getInt());
                    });
                    insertStageList.addAll(cloneStageList);
                }
            });
            if (CollectionsUtil.isNotEmpty(insertStageList)) {
                stageHelp.saveStageList(SaasMarkEnum.SAAS.getCode(), businessType, insertStageList, true);
            }

            // 获取普通阶段的主键id列表作为结束阶段的allow_reactive_stage
            Map<Long, List<Long>> ordinaryStageIdMap = insertStageList.stream()
                    .filter(stage -> Objects.equals(stage.getType(), StageTypeEnum.ORDINARY_STAGE.getType()))
                    .collect(Collectors.toMap(PaasStageEntity::getStageProcessId, stage -> Lists.newArrayList(stage.getId()),
                            (List<Long> oldList, List<Long> newList) -> {
                                oldList.addAll(newList);
                                return oldList;
                            }));

            // 更新阶段的allow_reactive_stage字段
            List<PaasStageEntity> updateStageList = new ArrayList<>();
            insertStageList.forEach(defaultStage -> {
                Integer stageType = defaultStage.getType();
                boolean isEndStage = Objects.equals(stageType, StageTypeEnum.SUCCESS_STAGE.getType())
                        || Objects.equals(stageType, StageTypeEnum.FAIL_STAGE.getType())
                        || Objects.equals(stageType, StageTypeEnum.CANCEL_STAGE.getType());
                if (isEndStage) {
                    List<Long> ordinaryStageIdList = ordinaryStageIdMap.get(defaultStage.getStageProcessId());
                    if (CollectionsUtil.isNotEmpty(ordinaryStageIdList)) {
                        defaultStage.setAllowReactiveStage(JSON.parseArray(JSON.toJSONString(ordinaryStageIdList)));
                        updateStageList.add(defaultStage);
                    }
                }
            });
            if (CollectionsUtil.isNotEmpty(updateStageList)) {
                stageHelp.updateStageBatch4Script(SaasMarkEnum.SAAS.getCode(), businessType, updateStageList);
            }

            // 初始化阶段任务
            List<StageWorkEntity> insertStageWorkList = new ArrayList<>();
            insertStageList.forEach(defaultStage -> {
                // 这里能通过阶段code去匹配对于的阶段work是因为前面初始化阶段的时候没有重新生成默认阶段的code
                // 获取这个阶段下定义的默认的阶段任务
                List<StageWorkEntity> stageWorkList = defaultWorkMap.get(defaultStage.getCode());
                if (CollectionsUtil.isNotEmpty(stageWorkList)) {
                    List<StageWorkEntity> cloneStageWorkList = (List<StageWorkEntity>) CloneUtil.deepClone(stageWorkList);
                    cloneStageWorkList.forEach(stageWork -> {
                        stageWork.setId(null);
                        stageWork.setCorpid(defaultStage.getCorpid());
                        stageWork.setFormId(defaultStage.getFormId());
                        stageWork.setStageProcessId(defaultStage.getStageProcessId());
                        stageWork.setStageId(defaultStage.getId());
                        stageWork.setStageCode(defaultStage.getCode());
                        stageWork.setAddTime(DateTimeUtil.getInt());
                        stageWork.setUpdateTime(DateTimeUtil.getInt());
                    });
                    insertStageWorkList.addAll(cloneStageWorkList);
                }
            });
            if (CollectionsUtil.isNotEmpty(insertStageWorkList)) {
                stageWorkModel.insertBatch(insertStageWorkList);
            }
        }
        LOG.warn("{}阶段初始化完成，耗时{}", xbbRefTypeEnum.getName(), DateTimeUtil.getInt() - currentTime);
        return StringConstant.SUCCESS;
    }
}
